// ##########################################################################
// #                                                                        #
// #                              CLOUDCOMPARE                              #
// #                                                                        #
// #  This program is free software; you can redistribute it and/or modify  #
// #  it under the terms of the GNU General Public License as published by  #
// #  the Free Software Foundation; version 2 or later of the License.      #
// #                                                                        #
// #  This program is distributed in the hope that it will be useful,       #
// #  but WITHOUT ANY WARRANTY; without even the implied warranty of        #
// #  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the          #
// #  GNU General Public License for more details.                          #
// #                                                                        #
// #          COPYRIGHT: EDF R&D / TELECOM ParisTech (ENST-TSI)             #
// #                                                                        #
// ##########################################################################

#ifndef CC_GENERIC_PRIMITIVE_HEADER
#define CC_GENERIC_PRIMITIVE_HEADER

// Local
#include "ccMesh.h"

class ccPointCloud;

//! Generic primitive interface
class QCC_DB_LIB_API ccGenericPrimitive : public ccMesh
{
  public:
	//! Default constructor
	/** Warning: the associated transformation is purely for display purpose by default.
	    Use 'ccHObject::applyGLTransformation_recursive' to 'apply' it to the mesh).
	    \param name name
	    \param transMat optional 3D transformation applied to the primitive vertices (can be set afterwards with ccDrawableObject::setGLTransformation + ccDrawableObject::applyGLTransformation_recursive)
	    \param uniqueID unique ID (handle with care)
	**/
	ccGenericPrimitive(QString           name     = QString(),
	                   const ccGLMatrix* transMat = nullptr,
	                   unsigned          uniqueID = ccUniqueIDGenerator::InvalidUniqueID);

	//! Returns type name (sphere, cylinder, etc.)
	virtual QString getTypeName() const = 0;

	//! Clones primitive
	virtual ccGenericPrimitive* clone() const = 0;

	//! Returns class ID
	inline CC_CLASS_ENUM getClassID() const override
	{
		return CC_TYPES::PRIMITIVE;
	}

	//! Sets primitive color (shortcut)
	/** \param col rgb color
	 **/
	virtual void setColor(const ccColor::Rgb& col);

	//! Add operator
	/** Warning: simply copies the input primitive vertices/triangles to this primitive mesh!
	 **/
	const ccGenericPrimitive& operator+=(const ccGenericPrimitive& prim);

	//! Whether drawing is dependent on 'precision' parameter
	virtual inline bool hasDrawingPrecision() const
	{
		return false;
	}

	//! Minimum drawing precision
	/** \warning Never pass a 'constant initializer' by reference
	 **/
	static const int MIN_DRAWING_PRECISION = 4;

	//! Sets drawing precision
	/** Warnings:
	    - steps should always be >= ccGenericPrimitive::MIN_DRAWING_PRECISION
	    - changes primitive content (calls ccGenericPrimitive::updateRepresentation)
	    - may fail if not enough memory!
	    \param steps drawing precision
	    \return success (false if not enough memory)
	**/
	virtual bool setDrawingPrecision(unsigned steps);

	//! Returns drawing precision (or 0 if feature is not supported)
	virtual inline unsigned getDrawingPrecision() const
	{
		return m_drawPrecision;
	}

	//! Returns the transformation that is currently applied to the vertices
	virtual inline ccGLMatrix& getTransformation()
	{
		return m_transformation;
	}

	//! Returns the transformation that is currently applied to the vertices (const version)
	virtual inline const ccGLMatrix& getTransformation() const
	{
		return m_transformation;
	}

	// inherited methods (ccHObject)
	const ccGLMatrix& getGLTransformationHistory() const override;

  protected:
	//! Inherited from ccGenericMesh
	void applyGLTransformation(const ccGLMatrix& trans) override;

	// inherited from ccMesh
	bool  toFile_MeOnly(QFile& out, short dataVersion) const override;
	bool  fromFile_MeOnly(QFile& in, short dataVersion, int flags, LoadedIDMap& oldToNewIDMap) override;
	short minimumFileVersion_MeOnly() const override;

	//! Builds primitive
	/** Transformation will be applied afterwards!
	    \return success
	**/
	virtual bool buildUp() = 0;

	//! Updates internal representation (as a mesh)
	/** Calls buildUp then applyTransformationToVertices.
	    \return success of buildUp
	**/
	virtual bool updateRepresentation();

	//! Inits internal structures
	/** Warning: resets all!
	 **/
	bool init(unsigned vertCount, bool vertNormals, unsigned faceCount, unsigned faceNormCount);

	//! Applies associated transformation to vertices
	/** Should be called only when (re)constructing primitive!
	 **/
	void applyTransformationToVertices();

	//! Finished 'clone' job (vertices color, etc.)
	/** \param primitive primitive to 'pimp'
	    \return pimped primitive
	**/
	ccGenericPrimitive* finishCloneJob(ccGenericPrimitive* primitive) const;

	//! Returns vertices
	ccPointCloud* vertices();

	//! Associated transformation (applied to vertices)
	/** Different from ccDrawableObject::m_glTrans!
	 **/
	ccGLMatrix m_transformation;

	//! Drawing precision (for primitives that support this feature)
	unsigned m_drawPrecision;
};

#endif // CC_GENERIC_PRIMITIVE_HEADER
